﻿#region Copyright information
// 
// Copyright © 2005-2013 Yongkee Cho. All rights reserved.
// 
// This code is a part of the Biological Object Library and governed under the terms of the
// GNU Lesser General  Public License (LGPL) version 2.1 which accompanies this distribution.
// For more information on the LGPL, please visit http://bol.codeplex.com/license.
// 
// - Filename: Complex.cs
// - Author: Yongkee Cho
// - Email: yongkeecho@gmail.com
// - Date Created: 2012-09-06 11:39 AM
// - Last Modified: 2013-01-25 3:59 PM
// 
#endregion
using System;

namespace BOL.Maths
{
    /// <summary>
    /// Represents a complex number.
    /// </summary>
    public struct Complex : IEquatable<Complex>
    {
        #region Public properties

        /// <summary>Gets or sets the real part of a complex number.</summary>
        public double A { get; private set; }

        /// <summary>Gets or sets the imaginary part of a complex number.</summary>
        public double B { get; private set; }

        /// <summary>Gets the magnitude (or modulous) of a complex number.</summary>
        public double Magnitude { get { return Math.Sqrt(A * A + B * B); } }

        #endregion

        #region Constructors

        /// <summary>
        /// Instantiates a complex number.
        /// </summary>
        public Complex(double a, double b) : this()
        {
            A = a;
            B = b;
        }

        public Complex(double a) : this(a, 0) { }

        #endregion

        #region operator implementations

        public static bool operator ==(Complex left, Complex right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(Complex left, Complex right)
        {
            return !left.Equals(right);
        }

        public static Complex operator +(Complex complex)
        {
            return complex;
        }

        public static Complex operator -(Complex complex)
        {
            return new Complex(-complex.A, -complex.B);
        }

        public static Complex operator +(Complex left, Complex right)
        {
            return new Complex(left.A + right.A, left.B + right.B);
        }

        public static Complex operator -(Complex left, Complex right)
        {
            return new Complex(left.A - right.A, left.B - right.B);
        }

        public static Complex operator *(Complex left, Complex right)
        {
            return new Complex(left.A * right.A - left.B * right.B, left.A * right.B + left.B * right.A);
        }

        public static Complex operator /(Complex left, Complex right)
        {
            double e, f;

            if (Math.Abs(right.B) < Math.Abs(right.A))
            {
                e = right.B / right.A;
                f = right.A + right.B * e;

                return new Complex((left.A + left.B * e) / f, (left.B - left.A * e) / f);
            }

            e = right.A / right.B;
            f = right.B + right.A * e;

            return new Complex((left.B + left.A * e) / f, (-left.A + left.B * e) / f);
        }

        #endregion

        #region Public methods

        public static Complex FromPolar(double modulus, double angle)
        {
            return new Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle));
        }

        public double Sqrt()
        {
            return A * A + B * B;
        }

        public static double Sqrt(Complex complex)
        {
            return complex.Sqrt();
        }

        public Complex Conjugate()
        {
            return new Complex(A, -B);
        }

        public static Complex Conjuage(Complex complex)
        {
            return new Complex(complex.A, -complex.B);
        }

        #endregion

        #region IEquatable<Complex> implementation

        public bool Equals(Complex other)
        {
            return A.Equals(other.A) & B.Equals(other.B);
        }

        #endregion

        #region Object overriden

        public override int GetHashCode()
        {
            return A.GetHashCode() ^ B.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Complex))
                throw new InvalidCastException("The 'obj' argument is not a Complex object.");

            return Equals((Complex)obj);
        }

        public override string ToString()
        {
            return String.Format("{0:G} + {1:G}i", A, B);
        }

        #endregion
    }
}
